﻿using SimpleBoard.Binary;
using SimpleBoard.Binary.Data;
using SimpleBoard.DependencyInjection;
using SimpleBoard.Runtime.Extensions;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Json;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace SimpleBoard.Runtime.Services
{
    public class SerialPortDataSource
    {
        public SerialPortDataSource(string portName, int boundRate)
        {
            this.serialPort = new System.IO.Ports.SerialPort(portName);
            this.serialPort.BaudRate = boundRate;

            // TODO 脏写法优化
            using var metaFile = File.OpenRead("App/Protocol.json");
            using var reader = new StreamReader(metaFile);
            var json = reader.ReadToEnd();
            reader.Close();
            this.dataFrameMeta = DataFrameMeta.Deserialize(json);
        }

        private readonly SerialPort serialPort;
        private readonly DataFrameMeta dataFrameMeta;
        private bool reading = false;
        private HttpClient httpClient = new HttpClient();
        public record UploadModel(Dictionary<string, string> Data, string Uid);

        public string? ServerUrl { get; set; }
        public string? Uid { get; set; }

        public void StartReadData()
        {
            this.serialPort.Open();
            reading = true;
            var readThread = new Thread(() =>
            {
                while (reading)
                {
                    var str = serialPort.ReadLine();
                    ParseData(str);
                }
            });
            readThread.Start();
        }

        private async void ParseData(string raw)
        {
            var data = raw.Split(',');
            var dict = new Dictionary<string, string>();
            for (var i = 0; i < data.Length; i++)
            {
                var meta = this.dataFrameMeta[i];

                if (meta.Name == "车速" && float.Parse(data[i]) > 100)
                {
                    serialPort.WriteLine("cmd:limit_speed");
                }

                dict.Add(meta.Name, data[i]);
                object value = meta.Type switch
                {
                    DataUnitType.String => data[i],
                    DataUnitType.Bool => bool.Parse(data[i]),
                    DataUnitType.Float32 => float.Parse(data[i]),
                    DataUnitType.Int32 => int.Parse(data[i]),
                    _ => throw new InvalidCastException()
                };

                var relatedBindings = BindableProperty.GetBindings(meta.Name);
                foreach (var relatedBinding in relatedBindings)
                {
                    await relatedBinding.Element.Dispatcher.BeginInvoke(() =>
                    {
                        relatedBinding.Element.SetPropertyValue(relatedBinding.PropertyName, value);
                    });
                }
            }

            if (string.IsNullOrEmpty(ServerUrl)) return;
            var result = await httpClient.PostAsJsonAsync(ServerUrl+"/api/Interactive/UploadData", new UploadModel(dict, Uid!));
            var content = await result.Content.ReadAsStringAsync();
        }
    }
}
